package com.battery.system.service.battery.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.battery.common.core.domain.AjaxResult;
import com.battery.common.core.text.Convert;
import com.battery.common.entity.BatteryEntity;
import com.battery.common.enums.*;
import com.battery.common.utils.Constants;
import com.battery.common.utils.DateUtils;
import com.battery.common.utils.StockUtils;
import com.battery.common.utils.dev.ChannelUtil;
import com.battery.common.utils.dev.WsDevUtils;
import com.battery.common.utils.excel.DeviceExcel;
import com.battery.common.utils.http.HttpClientJSONUtil;
import com.battery.common.utils.security.Md5Utils;
import com.battery.system.domain.*;
import com.battery.system.domain.BO.DevOnOff;
import com.battery.system.domain.BO.DeviceBO;
import com.battery.system.domain.BO.NotIssued;
import com.battery.system.domain.VO.*;
import com.battery.system.mapper.*;
import com.battery.system.service.battery.IDeviceService;
import com.battery.system.service.impl.BaseServiceImpl;
import com.install.rabbitmq.entity.DevMessageModel;
import com.install.rabbitmq.service.RabbitMqService;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.lang3.StringUtils;
import org.n3r.idworker.Sid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.*;

/**
 * 设备Service业务层处理
 *
 * @author battery
 * @date 2021-01-22
 */
@Service
public class DeviceServiceImpl extends BaseServiceImpl<Device> implements IDeviceService {


    private static final Logger LOGGER = LoggerFactory.getLogger(DeviceServiceImpl.class);


    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DeviceBasicsMapper deviceBasicsMapper;

    @Autowired
    private DeviceStatusMapper deviceStatusMapper;

    @Autowired
    private PartnerMapper partnerMapper;

    @Autowired
    private ProrelyMapper prorelyMapper;

    @Autowired
    private SysConfigMapper configMapper;

    @Autowired
    private UsedMapper usedMapper;

    @Autowired
    private UsedBasicsMapper usedBasicsMapper;


    @Autowired
    private Sid sid;


    @Autowired(required = false)
    private RabbitMqService rabbitMqService;


    // TODO TODO
    private static final String REQUEST_DOMAIN = "www.zjsuichong.com";

    /**
     * 查询设备
     *
     * @param id 设备ID
     * @return 设备
     */
    @Override
    public Device selectDeviceById(String id) {
        return deviceMapper.selectDeviceById(id);
    }

    /**
     * 查询设备列表
     *
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        device.setCreateTime(DateUtils.getNowDate());
        return deviceMapper.insertDevice(device);
    }

    /**
     * 修改设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        device.setUpdateTime(DateUtils.getNowDate());
        return deviceMapper.updateDevice(device);
    }

    /**
     * 删除设备对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(String ids) {
        return deviceMapper.deleteDeviceByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除设备信息
     *
     * @param id 设备ID
     * @return 结果
     */
    @Override
    public int deleteDeviceById(String id) {
        return deviceMapper.deleteDeviceById(id);
    }

    /**
     * 查询仓库中设备列表数据
     *
     * @param deviceBO
     * @return
     */
    @Override
    public List<DeviceVO> selectWarehouseList(DeviceBO deviceBO) {
        return deviceMapper.selectWarehouseList(deviceBO);
    }

    /**
     * 导入设备到仓库中
     *
     * @param list
     * @return
     */
    @Transactional
    @Override
    public String importExcel(List<DeviceExcel> list) {
        int size = list.size();
        int pointsDataLimit = 50;
        String result_ = "";
        Map<String, Object> result = new HashMap<>();
        int success = 0;
        int error = 0;
        int againImport = 0;
        List<DeviceExcel> newList = new ArrayList<DeviceExcel>();
        for (int i = 0; i < size; i++) {
            //分批次处理
            newList.add(list.get(i));
            if (pointsDataLimit == newList.size() || i == list.size() - 1) {
                result = execute(newList);
                success = success + Integer.parseInt(result.get("success").toString());
                error = error + Integer.parseInt(result.get("error").toString());
                againImport = againImport + Integer.parseInt(result.get("againImport").toString());
                newList.clear();
            }
        }
        String error_againImport = "";
        if (againImport > 0) {
            error_againImport = ",因设备SN已导入，导入失败" + againImport + "条数据";
        }
        result_ = "执行成功：" + success + ",总共失败：" + error + error_againImport;
        return result_;
    }

    /**
     * 划分设备
     *
     * @param device
     * @return
     */
    @Transactional
    @Override
    public int allotDevOne(Device device) {

        Partner partner = partnerMapper.selectByPrimaryKey(device.getPartnerId());

        Date date = DateUtils.getNowDate();
        device.setUpdateTime(date);
        device.setProjectId(partner.getProjectId());
        if (StringUtils.isNotBlank(device.getEventId())) {
            // 设备已选择了活动
            device.setIsActivity(YesOrNoEnum.YES.getCode());
        }
        deviceMapper.updateByPrimaryKeySelective(device);

        DeviceStatus deviceStatus = new DeviceStatus();
        deviceStatus.setDeviceId(device.getId());
        deviceStatus.setDeviceStatus(DeviceStatusEnum.TO_BE_DEPLOYED.getCode());
        deviceStatus.setDivideTime(date);
        deviceStatus.setAsideTime(date);
        return deviceStatusMapper.updateByPrimaryKeySelective(deviceStatus);
    }

    /**
     * 批量划分设备
     *
     * @param device
     * @return
     */
    @Transactional
    @Override
    public int allotDevAll(Device device) {
        String ids = device.getId();

        Partner partner = partnerMapper.selectByPrimaryKey(device.getPartnerId());
        String[] idsArr = ids.split(",");

        Date date = DateUtils.getNowDate();
        Device devUpdate = new Device();
        devUpdate.setUpdateTime(date);
        if (StringUtils.isNotBlank(device.getEventId())) {
            devUpdate.setIsActivity(YesOrNoEnum.YES.getCode()); // 活动设备
            devUpdate.setEventId(device.getEventId()); // 保存活动ID
        }
        devUpdate.setRemarks(device.getRemarks());
        devUpdate.setPartnerId(device.getPartnerId());
        devUpdate.setProjectId(partner.getProjectId());
        Example example = new Example(Device.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("id", Arrays.asList(idsArr));
        deviceMapper.updateByExampleSelective(devUpdate, example);

        DeviceStatus deviceStatus = new DeviceStatus();
        deviceStatus.setDeviceStatus(DeviceStatusEnum.TO_BE_DEPLOYED.getCode());
        deviceStatus.setDivideTime(date);
        deviceStatus.setAsideTime(date);
        Example exampleDevStaus = new Example(DeviceStatus.class);
        Example.Criteria criteriaDevStaus = exampleDevStaus.createCriteria();
        criteriaDevStaus.andIn("deviceId", Arrays.asList(idsArr));
        return deviceStatusMapper.updateByExampleSelective(deviceStatus, exampleDevStaus);
    }

    /**
     * 逻辑删除设备
     *
     * @param id
     * @return
     */
    @Override
    public int deleteLogicDeviceById(String id) {
        Device deviceUpdate = new Device();
        deviceUpdate.setId(id);
        deviceUpdate.setIsDeleted(YesOrNoEnum.YES.getCode());
        return deviceMapper.updateByPrimaryKeySelective(deviceUpdate);
    }


    @Override
    public List<DeviceVO> selectDeviceVOList(DeviceBO deviceBO) {
        return deviceMapper.selectDeviceVOList(deviceBO);
    }

    /**
     * 查询库存电池信息
     *
     * @param id
     * @return
     */
    @Override
    public List<BatteryEntity> getBatteryStockDetail(String id) {
        List<BatteryEntity> list = new ArrayList<>();
        DeviceBasics deviceBasics = deviceBasicsMapper.selectByPrimaryKey(id);
        String stockDetail = deviceBasics.getDetailStock();
        if (StringUtils.isNotBlank(stockDetail) && stockDetail.contains("id")) {
            // 库存详情为json格式数据
            Device device = deviceMapper.selectByPrimaryKey(id);
            String devType = device.getDevType();
            int maxSize = 0;
            if (DevTypeEnum.WS_DEV_4.getCode().equals(devType)) {
                // 4口设备
                maxSize = 4;
            } else if (DevTypeEnum.WS_DEV_6.getCode().equals(devType)) {
                // 6口设备
                maxSize = 6;
            } else if (DevTypeEnum.WS_DEV_9.getCode().equals(devType)) {
                // 9口设备
                maxSize = 9;
            } else if (DevTypeEnum.WS_DEV_12.getCode().equals(devType)) {
                // 12口设备
                maxSize = 12;
            }
            if (maxSize > 0) {
                list = StockUtils.getWsDevBatterys(stockDetail, maxSize, deviceBasics.getDetailStockTime());
            }
        }
        return list;
    }

    /**
     * 根据机柜SN获取对应的设备信息
     *
     * @param sn
     * @return
     */
    @Override
    public Device selectBySn(String sn) {
        Example example = new Example(Device.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("sn", sn);
        criteria.andEqualTo("isDeleted", YesOrNoEnum.NO.getCode());
        return deviceMapper.selectOneByExample(example);
    }

    @Override
    public Device selectDeviceBySn(String sn) {
        return deviceMapper.selectBySn(sn);
    }


    /**
     * WS设备进行同步设置操作
     *
     * @param obj 机柜发送内容
     * @return
     */
    @Transactional
    @Override
    public String wsDevSyncSettingOperation(JSONObject obj) {
        String sn = obj.getString("STATIONID"); // 机柜ID
        String soft_ver = obj.getString("SOFT_VER"); // 硬件版本
        Prorely prorely = prorelyMapper.selectBySn(sn);
        LOGGER.info("------> 机柜SN为" + sn + ",进行syncSetting操作 <------");
        String service = ""; // 连接域名
        Integer port = null; // 端口号
        Integer bps = null;
        Integer heartbeat = null;
        Integer batLine = null; // 正常租借是否判定线好坏 0 否 1 是
        Integer normalBorrow = null;
        Integer appointBorrow = null;
        if (prorely != null) {
            service = prorely.getService();
            port = prorely.getPort();
            bps = prorely.getBps();
            heartbeat = prorely.getHeartbeat();
            batLine = prorely.getBatLine();
            normalBorrow = prorely.getNormalBorrow();
            appointBorrow = prorely.getAppointBorrow();
        } else {
            service = Constants.sys_wsDev_basicsDomain;
            port = Integer.parseInt(Constants.sys_wsDev_basicsPort);
            bps = Integer.parseInt(Constants.sys_wsDev_basicsBps);
            heartbeat = Integer.parseInt(Constants.sys_wsDev_basicsHeartbeat);
            batLine = 0;
            normalBorrow = 30;
            appointBorrow = 30;
        }
        String ip = "10.0.0.1";
        Device device = deviceMapper.selectBySn(sn);
        if (device != null) {
            // 更新设备详细信息
            DeviceBasics devBasicsUpdate = new DeviceBasics();
            devBasicsUpdate.setDeviceId(device.getId());
            devBasicsUpdate.setUsableBattery(obj.getInteger("USABLE_BATTERY"));
            devBasicsUpdate.setInStockTotal(obj.getInteger("TOTAL"));
            devBasicsUpdate.setUpdateNumTime(DateUtils.getNowDate());
            devBasicsUpdate.setFirmwareVersion(soft_ver);
            deviceBasicsMapper.updateByPrimaryKeySelective(devBasicsUpdate);
        }
        Long time = System.currentTimeMillis() / 1000;
        LOGGER.info("------> 机柜SN为" + sn + ",进行syncSetting操作 end <------");
        return "TIME:" + time + ";DOMAIN:" + service + ";IP:" + ip + ";PORT:" + port + ";BPS:" + bps + ";BAT_LINE:" + batLine
                + ";HEATBEAT:" + heartbeat + ";NORMAL_BORROW:" + normalBorrow + ";APPOINT_BORROW:" + appointBorrow;
    }

    /**
     * 归还确认
     *
     * @param obj
     * @return
     */
    @Transactional
    @Override
    public String wsRentConfirm(JSONObject obj) {
        String batterySn = obj.getString("ID"); // 电池ID
        Integer status = obj.getInteger("STATUS"); // TODO 状态STATUS: 0  接受到接应答
        String sn = obj.getString("STATIONID");

        LOGGER.info("------> 机柜SN为" + sn + ",[rentConfirm] <------");

        Long borrowId = obj.getLong("ORDERID");
        String lease_id = "borrow" + "_" + sn + "_" + borrowId;
        // 查询对应的租借记录
        Example example = new Example(UsedBasics.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("leaseId", lease_id);
        example.orderBy("rentDate").desc();
        UsedBasics usedBasics = usedBasicsMapper.selectOneByExample(example);

        if (StringUtils.isNotBlank(batterySn) && !"0000000000".equals(batterySn)) {
            if (status.intValue() == 0) {
                // 第一次握手，状态STATUS: 0  接受到接应答, 查询对应初始化订单，如果存在，则反馈。
                if (usedBasics != null) {
                    // 存在对应的租借订单
                    return "ERRCODE:0;ERRMSG:none;ORDERID:" + borrowId + ";ACK:rent_confirm";
                }
            } else if (status.intValue() == 1) {
                // 第二次握手，STATUS: 1  表示借出成功
                // 租借成功，更新租借状态，同时发送租借确认
                if (usedBasics != null) {
                    // 记录租借卡槽与电池编号
                    Integer slot = obj.getInteger("SLOT"); // 卡槽位
                    UsedBasics usedBasicsUpdate = new UsedBasics();
                    usedBasicsUpdate.setRentSlotNo(slot); // 租借设备卡槽位
                    usedBasicsUpdate.setBatterySn(batterySn); // 租借电池编号
                    usedBasicsUpdate.setUsedId(usedBasics.getUsedId());
                    usedBasicsMapper.updateByPrimaryKeySelective(usedBasicsUpdate);
                    // 记录租借记录租借状态
                    Used usedUpdate = new Used();
                    usedUpdate.setId(usedBasics.getUsedId());
                    usedUpdate.setLeaseState(LeaseStateEnum.SUCCESS.getCode()); // 租借成功
                    usedMapper.updateByPrimaryKeySelective(usedUpdate);
                    // 需要发送远程命令
                    try {
                        // 同步详细库存信息
                        // 放到消息队列里面
                        DevMessageModel messageModel = new DevMessageModel();
                        messageModel.setSn(sn);
                        messageModel.setCommand("sync_battery");
                        messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                        LOGGER.info("------> 机柜SN为" + sn + ",[rentConfirm],同步详细库存信息,等待6秒钟 <------");
                        messageModel.setSleep(6); // 停止6秒钟
                        rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return "ERRCODE:0;ERRMSG:none;ORDERID:" + borrowId + ";ACK:rent_confirm";
                } else {
                    // 需要发送远程命令
                    try {
                        // 同步详细库存信息
                        // 放到消息队列里面
                        DevMessageModel messageModel = new DevMessageModel();
                        messageModel.setSn(sn);
                        messageModel.setCommand("sync_battery");
                        messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                        messageModel.setSleep(6); // 停止6秒钟
                        rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } else {
                // 租借失败，没有可用电池。如果是免押租借，则撤销订单。
                if (usedBasics != null) {
                    // 更新租借状态为失败
                    Used used = usedMapper.selectByPrimaryKey(usedBasics.getUsedId());
                    Used usedUpdate = new Used();
                    usedUpdate.setId(used.getId());
                    usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode()); // 租借失败
                    usedMapper.updateByPrimaryKeySelective(usedUpdate);

                    // TODO 同时需要发送同步库存信息
                    LOGGER.info("------> 机柜SN为" + sn + ",[rentConfirm],租借失败,同步详细库存信息,等待5秒钟 <------");
                    DevMessageModel messageModel = new DevMessageModel();
                    messageModel.setSn(sn);
                    messageModel.setCommand("sync_battery");
                    messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                    messageModel.setSleep(5); // 停止6秒钟
                    rabbitMqService.sendMessage(JSON.toJSONString(messageModel));

                    if (BorrowModeEnum.FREE_DEPOSIT.type.intValue() == used.getBorrowMode().intValue()) {
                        // 授权订单撤销
                        // TODO 租借失败之后，如果是免押租借，需要撤销掉对应的订单
                        // 是授权租借订单,租借失败，必然需要进行撤销，或解冻
                        // 发送远程请求解冻或撤销订单
                        // 异步执行
                        JSONObject object = new JSONObject();
                        object.put("used_id", used.getId());
                        String salt = Constants.ws_borrow_slat;
                        String before = used.getId() + salt;
                        object.put("sign", Md5Utils.hash(before));
                        try {
                            HttpClientJSONUtil.postHttpJsonDataAsyn("https://" + REQUEST_DOMAIN + "/min/wx/request/revokeUsed", object);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    return "ERRCODE:0;ERRMSG:none;ORDERID:" + borrowId + ";ACK:rent_confirm";
                }
            }
        }
        return "";
    }


    /**
     * WS设备心跳处理
     *
     * @param obj
     * @return
     */
    @Transactional
    @Override
    public String wsHeartbeat(JSONObject obj) {
        String sn = obj.getString("STATIONID"); // 机柜SN
        String ch = obj.getString("CH"); // 机柜库存信息
        String csq = obj.getString("CSQ"); // 信号值 0~31
        LOGGER.info("------> 机柜SN为" + sn + ",进行[heartbeat],其库存信息为" + ch + " <------");
        Device device = deviceMapper.selectBySn(sn);
        String result = "ERRCODE:0;ERRMSG:none;ACK:heartbeat";
        if (device != null) {
            try {
                // 获取心跳库存信息
                DeviceBasics deviceBasics = deviceBasicsMapper.selectByPrimaryKey(device.getId());
                if (deviceBasics != null) {
                    if (StringUtils.isBlank(deviceBasics.getDetailStock())) {
                        // 库存详情信息为空,发送同步库存命令
//                        Long time = System.currentTimeMillis() / 1000;
//                        result = "EVENT_CODE:58;MSG_ID:" + time;
                        try {
                            DevMessageModel messageModel = new DevMessageModel();
                            messageModel.setSn(sn);
                            messageModel.setCommand("sync_battery");
                            messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                            LOGGER.info("------> 机柜SN为" + sn + ",[wsHeartbeat],强弹确认,等待1秒钟 <------");
                            messageModel.setSleep(1); // 停止2秒钟
                            rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                String heartBeatStock = WsDevUtils.getHeartBeatStock(ch);
                DeviceBasics devBasicsUpdate = new DeviceBasics();
                devBasicsUpdate.setDeviceId(device.getId());
                devBasicsUpdate.setUsableBattery(obj.getInteger("USABLE_BATTERY"));
                devBasicsUpdate.setInStockTotal(obj.getInteger("TOTAL"));
                devBasicsUpdate.setUpdateNumTime(DateUtils.getNowDate());
                devBasicsUpdate.setStock(heartBeatStock);
                devBasicsUpdate.setCsq(csq);
                devBasicsUpdate.setStockUpdateTime(DateUtils.getNowDate());
                deviceBasicsMapper.updateByPrimaryKeySelective(devBasicsUpdate);

                // 心跳远程结束订单
                JSONObject object = new JSONObject();
                object.put("device_id", device.getId());
                String salt = Constants.ws_borrow_slat;
                String before = device.getId() + salt;
                object.put("sign", Md5Utils.hash(before));
                HttpClientJSONUtil.postHttpJsonDataAsyn("https://" + REQUEST_DOMAIN + "/min/wx/request/wsHeartbeatBattery", object);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * WS设备同步库存处理
     *
     * @param obj
     * @return
     */
    @Override
    public String wsSyncBattery(JSONObject obj) {
        String sn = obj.getString("STATIONID");
        Device device = deviceMapper.selectBySn(sn);
        if (device != null) {
            try {
                // 保存详情库存信息
                String detailStock = WsDevUtils.getSyncBatteryStock(obj);
                LOGGER.info("------> 机柜SN为" + sn + ",[syncBattery],其库存详情为：" + detailStock + "<------");
                DeviceBasics devBasicsUpdate = new DeviceBasics();
                devBasicsUpdate.setDeviceId(device.getId());
                devBasicsUpdate.setUsableBattery(obj.getInteger("USABLE_BATTERY"));
                devBasicsUpdate.setInStockTotal(obj.getInteger("TOTAL"));
                devBasicsUpdate.setUpdateNumTime(DateUtils.getNowDate());
                devBasicsUpdate.setDetailStock(detailStock);
                devBasicsUpdate.setDetailStockTime(DateUtils.getNowDate());
                deviceBasicsMapper.updateByPrimaryKeySelective(devBasicsUpdate);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "ERRCODE:0;ERRMSG:none;ACK:sync_battery";
    }

    /**
     * WS设备归还确认处理
     *
     * @param obj
     * @return
     */
    @Transactional
    @Override
    public String wsReturnBack(JSONObject obj) {
        String sn = obj.getString("STATIONID"); // 归还机柜SN
        String batterySn = obj.getString("ID"); // 归还电池ID
        Integer slot = obj.getInteger("SLOT"); // 归还电池ID
        LOGGER.info("------> 机柜SN为" + sn + ",[returnBack],batterySn:" + batterySn + ",SLOT:" + slot + " <------");

        Device device = deviceMapper.selectBySn(sn);
        if (device == null) {
            return "ERRCODE:0;ERRMSG:none;ID:" + batterySn + ";ACK:return_back";
        }
        // 通过电池ID 查询正在借用中的订单
        UsedBasics usedBasics = usedBasicsMapper.selectOnLoadByBatterySn(batterySn);
        if (usedBasics == null) {
            try {
                // 同步详细库存信息
                // 放到消息队列里面
                LOGGER.info("------> 机柜SN为" + sn + ",[returnBack],同步详细库存信息,等待7秒钟 <------");
                DevMessageModel messageModel = new DevMessageModel();
                messageModel.setSn(sn);
                messageModel.setCommand("sync_battery");
                messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                messageModel.setSleep(7); // 停止7秒钟
                rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "ERRCODE:0;ERRMSG:none;ID:" + batterySn + ";ACK:return_back";
        }
        // 存在正在使用中的租借订单, 将归还的电池消息保存到表中
        UsedBasics usedBasicsUpdate = new UsedBasics();
        usedBasicsUpdate.setUsedId(usedBasics.getUsedId());
        usedBasicsUpdate.setBackDeviceId(device.getId());
        usedBasicsUpdate.setBackDeviceSn(sn); // 归还设备sn
        usedBasicsUpdate.setBackSlotNo(slot); // 归还的设备槽位
        usedBasicsMapper.updateByPrimaryKeySelective(usedBasicsUpdate);
        // 异步通知归还操作，结束订单
        JSONObject object = new JSONObject();
        object.put("used_id", usedBasics.getUsedId());
        object.put("sn", sn); // 归还的机柜SN
        object.put("batterySn", batterySn); // 电池ID
        String salt = Constants.ws_borrow_slat;
        String before = usedBasics.getUsedId() + sn + batterySn + salt;
        object.put("sign", Md5Utils.hash(before));
        try {
            HttpClientJSONUtil.postHttpJsonDataAsyn("https://" + REQUEST_DOMAIN + "/min/wx/request/wsEndUsed", object);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    @Override
    public List<Device> selectDeviceListByAccountId(String id) {
        return deviceMapper.selectDeviceListByAccountId(id);
    }

    @Override
    public DeviceVV deleteDeviceVVById(String devId) {
        DeviceVV deviceVV = deviceMapper.deleteDeviceVVById(devId);
        if (deviceVV != null) {
            deviceVV.setDetailStock(WsDevUtils.getRealStock(deviceVV.getDetailStock(), deviceVV.getLockBatterys(), deviceVV.getAll()));
        }
        return deviceVV;
    }

    @Override
    public int deviceDeployments(JSONObject json, String where) {
        Date date = new Date();
        String merchantId = json.getString("merchantId");
        String storeId = json.getString("storeId");
        deviceStatusMapper.updateDeviceStatusByList(date, where);
        return deviceMapper.updateDeviceByList(date, where, merchantId, storeId);
    }

    @Override
    public List<DevOnOff> selectByOnOff(String where) {
        return deviceMapper.selectByOnOff(where);
    }

    @Override
    public List<NotIssued> selectByNotIssued(String id, Integer hour) {
        return deviceMapper.selectByNotIssued(id, hour);
    }

    @Override
    public List<NotIssued> selectByBubao(String id, int num) {
        return deviceMapper.selectByBubao(id, num);
    }

    @Override
    public BatteryNumber getWsDevInStockNumByStoreId(String storeId) {
        return deviceMapper.getWsDevInStockNumByStoreId(storeId);
    }

    /**
     * 设备返回仓库操作
     *
     * @param id
     * @return
     */
    @Override
    public int returnWarehouse(String id) {
        // 更新
        DeviceStatus deviceStatusUpdate = new DeviceStatus();
        deviceStatusUpdate.setDeviceId(id);
        deviceStatusUpdate.setDeviceStatus(DeviceStatusEnum.TO_BE_DIVIDED.getCode());
        deviceStatusMapper.returnWarehouse(deviceStatusUpdate);

        Device deviceUpdate = new Device();
        deviceUpdate.setId(id);

        return deviceMapper.returnWarehouse(deviceUpdate);
    }

    /**
     * 批量设置活动
     *
     * @param device
     * @return
     */
    @Override
    public int devChoseEvents(Device device) {
        String ids = device.getId();

        String[] idsArr = ids.split(",");

        Date date = DateUtils.getNowDate();
        Device devUpdate = new Device();
        devUpdate.setUpdateTime(date);
        devUpdate.setIsActivity(YesOrNoEnum.YES.getCode()); // 活动设备
        devUpdate.setEventId(device.getEventId()); // 保存活动ID
        devUpdate.setRemarks(device.getRemarks());
        Example example = new Example(Device.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("id", Arrays.asList(idsArr));
        return deviceMapper.updateByExampleSelective(devUpdate, example);
    }

    @Override
    public List<ActivityCount> selectUsedByActivity(Map<String, String> map) {
        return deviceMapper.selectUsedByActivity(map);
    }

    @Override
    public void updateDeviceToParnter(String devs, String id) {
        deviceMapper.updateDeviceToParnter(Convert.toStrArray(devs), id);
    }


    /**
     * WS设备操作
     *
     * @param obj
     * @param ctxId
     * @param context
     * @return
     */
    @Override
    public String wsLogin(JSONObject obj, String ctxId, ChannelHandlerContext context) {
        String response = "";
        String imei = obj.getString("MAC");
        LOGGER.info("------> mac地址为" + imei + ",进行login操作 <------");
        Example example = new Example(Prorely.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("imei", imei);
        Prorely prorely = prorelyMapper.selectOneByExample(example);
        if (prorely != null) {
            Prorely prorelyUpdate = new Prorely();
            prorelyUpdate.setId(prorely.getId());
            prorelyUpdate.setCtxId(ctxId);
            prorelyMapper.updateByPrimaryKeySelective(prorelyUpdate);

            // 存在依赖信息，则该设备为该项目设备
            String sn = prorely.getSn();
            Device device = deviceMapper.selectBySn(prorely.getSn());
            if (device != null) {
                Device deviceUpdate = new Device();
                deviceUpdate.setId(device.getId());
                Integer isOFFline = YesOrNoEnum.NO.getCode();
                deviceUpdate.setDevStatus(isOFFline);
                deviceMapper.updateByPrimaryKeySelective(deviceUpdate);

                // 更新设备详细信息，同时将对应信息存储到数据库中
                DeviceBasics deviceBasicsUpdate = new DeviceBasics();
                deviceBasicsUpdate.setDeviceId(device.getId());
                deviceBasicsUpdate.setCcid(obj.getString("CCID")); // 更新流量卡信息
                deviceBasicsUpdate.setUsableBattery(obj.getInteger("USABLE_BATTERY"));
                deviceBasicsUpdate.setInStockTotal(obj.getInteger("TOTAL"));
                deviceBasicsMapper.updateStockIsNull(deviceBasicsUpdate);
            }
            // 建立起绑定关系
            ChannelUtil.put(sn, context.channel()); // 进行绑定操作
            try {
                // 同步详细库存信息
                // 放到消息队列里面
                DevMessageModel messageModel = new DevMessageModel();
                messageModel.setSn(sn);
                messageModel.setCommand("sync_battery");
                messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                LOGGER.info("------> 机柜SN为" + sn + ",[wsLogin],登录操作,等待16秒钟 <------");
                messageModel.setSleep(16); // 停止16秒钟
                rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
            } catch (Exception e) {
                e.printStackTrace();
            }
            response = "BINDADDRESS:1;STATIONID:" + sn; // 登录回复
            LOGGER.info("login操作返回-》" + response);
        }
        return response;
    }

    /**
     * WS设备强弹
     *
     * @param obj
     * @return
     */
    @Override
    public String popupConfirm(JSONObject obj) {
        Integer slot = obj.getInteger("SLOT");
        String sn = obj.getString("STATIONID");
        Integer orderid = obj.getInteger("ORDERID");
        LOGGER.info("------> 机柜SN为" + sn + ",[popupConfirm] <------");
        if (orderid > 0) {
            Long borrowId = obj.getLong("ORDERID");
            String lease_id = "popup" + "_" + sn + "_" + slot + "_" + borrowId;
            // 查询对应的租借记录
            Example example = new Example(UsedBasics.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("leaseId", lease_id);
            example.orderBy("rentDate").desc();
            UsedBasics usedBasics = usedBasicsMapper.selectOneByExample(example);
            if (usedBasics != null) {
                Used usedUpdate = new Used();
                usedUpdate.setId(usedBasics.getUsedId());
                usedUpdate.setLeaseState(LeaseStateEnum.SUCCESS.getCode()); // 租借成功
                usedMapper.updateByPrimaryKeySelective(usedUpdate);
                // 需要发送远程命令
                try {
                    // 同步详细库存信息
                    // 放到消息队列里面
                    DevMessageModel messageModel = new DevMessageModel();
                    messageModel.setSn(sn);
                    messageModel.setCommand("sync_battery");
                    messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                    LOGGER.info("------> 机柜SN为" + sn + ",[popupConfirm],强弹租借确认,等待8秒钟 <------");
                    messageModel.setSleep(8); // 停止8秒钟,保证电池数据的正确性
                    rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            String popup_return_request = "EVENT_CODE:55;ERRMSG:none;SLOT:" + slot + ";ACK:popup_confirm";
            return popup_return_request;
        } else {
            Device device = deviceMapper.selectBySn(sn);
            if (device != null) {
                try {
                    // 同步详细库存信息
                    // 放到消息队列里面
                    DevMessageModel messageModel = new DevMessageModel();
                    messageModel.setSn(sn);
                    messageModel.setCommand("sync_battery");
                    messageModel.setContent("EVENT_CODE:58;MSG_ID:");
                    LOGGER.info("------> 机柜SN为" + sn + ",[popupConfirm],强弹确认,等待8秒钟 <------");
                    messageModel.setSleep(8); // 停止2秒钟
                    rabbitMqService.sendMessage(JSON.toJSONString(messageModel));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 更新设备详细信息，同时将对应信息存储到数据库中
                DeviceBasics deviceBasicsUpdate = new DeviceBasics();
                deviceBasicsUpdate.setDeviceId(device.getId());
                deviceBasicsUpdate.setCcid(obj.getString("CCID")); // 更新流量卡信息
                deviceBasicsUpdate.setUsableBattery(obj.getInteger("USABLE_BATTERY"));
                deviceBasicsUpdate.setInStockTotal(obj.getInteger("TOTAL"));
                deviceBasicsMapper.updateStockIsNull(deviceBasicsUpdate);
            }
            String popup_return_request = "EVENT_CODE:55;ERRMSG:none;SLOT:" + slot + ";ACK:popup_confirm";
            return popup_return_request;
        }
    }

    /**
     * 校验该门店底下是否存在设备
     *
     * @param storeId
     * @return
     */
    @Override
    public boolean checkDevIsCzByStoreId(String storeId) {

        Example example = new Example(Device.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("storeId", storeId);
        criteria.andEqualTo("isDeleted", 0);
        return deviceMapper.selectCountByExample(example) > 0;
    }


    /**
     * 设备变更商户
     *
     * @param storeId
     * @param merchantId
     * @return
     */
    @Override
    public int changeDevMerchant(String storeId, String merchantId) {
        Example example = new Example(Device.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("storeId", storeId);
        criteria.andEqualTo("isDeleted", YesOrNoEnum.NO.getCode());
        Device deviceUpdate = new Device();
        deviceUpdate.setMerchantId(merchantId);
        return deviceMapper.updateByConditionSelective(deviceUpdate, example);
    }

    /**
     * 【设备-调回功能块】--- 下级代理列表，展示下级代理闲置设备数量
     *
     * @param partnerId
     * @return
     */
    @Override
    public List<PartnerNoUseDevVO> selectLowerPartnerForNoUseDev(String partnerId, String partnerName) {
        return deviceMapper.selectLowerPartnerForNoUseDev(partnerId, partnerName);
    }

    /**
     * 【设备-调回功能块】 ---下级代理的闲置设备，展示下级代理闲置设备
     *
     * @param lowerPartnerId
     * @param sn
     * @return
     */
    @Override
    public List<DevNoUseVO> selectNoUseDevsByLowerPartner(String lowerPartnerId, String sn) {
        return deviceMapper.selectNoUseDevsByLowerPartner(lowerPartnerId, sn);
    }

    /**
     * 批量调回设备
     *
     * @param ids
     * @param accountId
     * @return
     */
    @Transactional
    @Override
    public AjaxResult recallDevs(String[] ids, String accountId) {

        // 更新设备信息
        Example devUpdateExample = new Example(Device.class);
        Example.Criteria criteria = devUpdateExample.createCriteria();
        criteria.andIn("id", Arrays.asList(ids));
        Device deviceUpdate = new Device();
        deviceUpdate.setPartnerId(accountId);
        deviceMapper.updateByExampleSelective(deviceUpdate, devUpdateExample);

        Example deviceStatusUpdateExample = new Example(DeviceStatus.class);
        Example.Criteria devStatusCriteria = deviceStatusUpdateExample.createCriteria();
        devStatusCriteria.andIn("deviceId", Arrays.asList(ids));
        DeviceStatus deviceStatusUpdate = new DeviceStatus();
        deviceStatusUpdate.setAsideTime(DateUtils.getNowDate());
        deviceStatusUpdate.setDeviceStatus(DeviceStatusEnum.TO_BE_DEPLOYED.getCode());
        deviceStatusMapper.updateByExampleSelective(deviceStatusUpdate, deviceStatusUpdateExample);

        return AjaxResult.success();
    }

    /**
     * 调拨设备
     *
     * @param ids
     * @param lowerPartnerId
     * @return
     */
    @Override
    public AjaxResult allotDevs(String[] ids, String lowerPartnerId) {
        // 更新设备信息
        Example devUpdateExample = new Example(Device.class);
        Example.Criteria criteria = devUpdateExample.createCriteria();
        criteria.andIn("id", Arrays.asList(ids));
        Device deviceUpdate = new Device();
        deviceUpdate.setPartnerId(lowerPartnerId);
        deviceMapper.updateByExampleSelective(deviceUpdate, devUpdateExample);

        Example deviceStatusUpdateExample = new Example(DeviceStatus.class);
        Example.Criteria devStatusCriteria = deviceStatusUpdateExample.createCriteria();
        devStatusCriteria.andIn("deviceId", Arrays.asList(ids));
        DeviceStatus deviceStatusUpdate = new DeviceStatus();
        deviceStatusUpdate.setAsideTime(DateUtils.getNowDate());
        deviceStatusUpdate.setDeviceStatus(DeviceStatusEnum.TO_BE_DEPLOYED.getCode());
        deviceStatusMapper.updateByExampleSelective(deviceStatusUpdate, deviceStatusUpdateExample);
        return AjaxResult.success();
    }

    /**
     * 查询在线设备，根据门店分组
     *
     * @param where
     * @return
     */
    @Override
    public List<DevVO> onLineDevList(String where, String orderBy) {
        return deviceMapper.onLineDevList(where, orderBy);
    }

    /**
     * 查询设备，根据门店分组数量
     *
     * @param where
     * @return
     */
    @Override
    public int onLineDevListCount(String where) {
        return deviceMapper.onLineDevListCount(where);
    }


    @Override
    public List<DevInfoVO> devListByStoreId(String where) {
        return deviceMapper.devListByStoreId(where);
    }


    @Override
    public List<DeviceVO> listDevIncome(DeviceBO deviceBO) {
        return deviceMapper.listDevIncome(deviceBO);
    }


    @Override
    public int devRecoveryById(String id) {
        return deviceMapper.devRecoveryById(id);
    }

    /**
     * 查询平台所有机柜数量
     *
     * @return
     */
    @Override
    public Integer selectAllCount() {
        Example example = new Example(Device.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("isDeleted", YesOrNoEnum.NO.getCode());
        return deviceMapper.selectCountByExample(example);
    }

    /**
     * 总设备的统计分析
     *
     * @return
     */
    @Override
    public DevAnalysisVO selectDevAnalysis() {
        return deviceMapper.selectDevAnalysis();
    }

    /**
     * onLineSpecialDevList
     *
     * @param where
     * @param onOrderBy
     * @return
     */
    @Override
    public List<DevVO> onLineSpecialDevList(String where, String onOrderBy) {
        return deviceMapper.onLineSpecialDevList(where, onOrderBy);
    }

    /**
     * 批量回收设备
     *
     * @param where
     * @return
     */
    @Transactional
    @Override
    public int devBatchRecovery(String where) {
        Date date = DateUtils.getNowDate();
        deviceStatusMapper.batchUpdateDeviceStatusByList(date, where);
        return deviceMapper.devBatchRecovery(where);
    }

    /**
     * 获取该门店下的可回收的设备
     *
     * @param storeId
     * @return
     */
    @Override
    public List<Device> getRecyclableDevList(String storeId) {
        return deviceMapper.getRecyclableDevList(storeId);
    }

    /**
     * 获取闲置设备（新接口，有分页）
     *
     * @param where
     * @return
     */
    @Override
    public List<Device> getAsideDevs(String where) {
        return deviceMapper.getAsideDevs(where);
    }

    /**
     * 设备回收
     *
     * @param id
     * @return
     */
    @Transactional
    @Override
    public int recoveryDev(String id) {
        Date date = DateUtils.getNowDate();
        DeviceStatus deviceStatus = new DeviceStatus();
        deviceStatus.setDeviceId(id);
        deviceStatus.setDeviceStatus(1);
        deviceStatus.setAsideTime(date);
        deviceStatus.setRecoveryTime(date);
        deviceStatusMapper.updateByPrimaryKeySelective(deviceStatus);
        return deviceMapper.devRecoveryById(id);
    }


    @Transactional
    @Override
    public int returnWarehouses(String ids) {
        String[] idsArr = ids.split(",");
        DeviceStatus deviceStatusUpdate = new DeviceStatus();
        deviceStatusUpdate.setDeviceStatus(DeviceStatusEnum.TO_BE_DIVIDED.getCode());
        Example example = new Example(DeviceStatus.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("deviceId", Arrays.asList(idsArr));
        deviceStatusMapper.updateByExampleSelective(deviceStatusUpdate, example);
        return deviceMapper.returnWarehousesByIds(Convert.toStrArray(ids));
    }

    /**
     * 根据条件查询闲置设备数量
     *
     * @param where
     * @return
     */
    @Override
    public int asideDevCount(String where) {
        return deviceMapper.asideDevCount(where);
    }

    private Map<String, Object> execute(List<DeviceExcel> list) {
        Map<String, Object> result = new HashMap<>();
        if (list != null && list.size() > 0) {
            Date date = new Date();
            int size = list.size();
            int success = 0;
            int error = 0;
            int againImport = 0;
            DeviceExcel excel = null;
            Device device = null;
            DeviceBasics basics = null;
            DeviceStatus status = null;
            for (int i = 0; i < size; i++) {
                excel = list.get(i);
                device = deviceMapper.selectBySn(excel.getSn());
                if (device == null) {
                    String devType = excel.getDevType();
                    if (DevTypeEnum.WS_DEV_6.getCode().equals(devType) ||
                            DevTypeEnum.WS_DEV_9.getCode().equals(devType) ||
                            DevTypeEnum.WS_DEV_12.getCode().equals(devType) ||
                            DevTypeEnum.WS_DEV_4.getCode().equals(devType) ||
                            DevTypeEnum.R_LINE.getCode().equals(devType)
                    ) {
                        String deviceId = sid.nextShort();
                        // 创建核心设备表
                        device = new Device();
                        device.setId(deviceId);
                        device.setSn(excel.getSn());
                        device.setDevType(excel.getDevType());
                        device.setCreateTime(date);


                        basics = new DeviceBasics();
                        basics.setDeviceId(deviceId);
                        device.setDevStatus(YesOrNoEnum.YES.getCode()); // 设置为离线
                        if (DevTypeEnum.WS_DEV_6.getCode().equals(devType)) {
                            basics.setAllBattery(6);
                        } else if (DevTypeEnum.WS_DEV_4.getCode().equals(devType)) {
                            basics.setAllBattery(4);
                        } else if (DevTypeEnum.WS_DEV_12.getCode().equals(devType)) {
                            basics.setAllBattery(12);
                        } else if (DevTypeEnum.WS_DEV_9.getCode().equals(devType)) {
                            basics.setAllBattery(9);
                        } else if (DevTypeEnum.R_LINE.getCode().equals(devType)) {
                            basics.setAllBattery(0);
                            device.setDevStatus(YesOrNoEnum.NO.getCode()); // 设置为在线
                        }
                        deviceMapper.insertSelective(device);

                        deviceBasicsMapper.insertSelective(basics);

                        status = new DeviceStatus();
                        status.setDeviceId(deviceId);
                        status.setCreatedTime(date);
                        status.setDeviceStatus(DeviceStatusEnum.TO_BE_DIVIDED.getCode());
                        deviceStatusMapper.insertSelective(status);
                        success = success + 1;
                    } else {
                        error = error + 1;
                        continue;
                    }
                } else {
                    // 该设备SN已经导入了
                    error = error + 1;
                    againImport = againImport + 1;
                    continue;
                }
            }
            result.put("success", success);
            result.put("error", error);
            result.put("againImport", againImport);
        } else {
            result.put("success", 0);
            result.put("error", 0);
            result.put("againImport", 0);
        }
        return result;
    }
}
